﻿using System;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Data.Entity.Validation;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Sharp.Domain.Repositories;
using System.Collections.Generic;

namespace Sharp.Domain.Repository.EF
{
    /// <summary>
    /// Entity Framework 的仓储实现
    /// </summary>
    public class EntityFrameworkRepositoryContext : RepositoryContext, IEntityFrameworkRepositoryContext
    {
        #region Private Fields
        private DbContext _efContext;
        private readonly object _sync = new object();
        #endregion

        /// <summary>
        /// Entity Framework 的仓储实现构造函数
        /// </summary>
        /// <param name="efContext"></param>
        public EntityFrameworkRepositoryContext(DbContext efContext)
        {
#if DEBUG
            if (efContext == null)
            {
                throw new NotImplementedException("为实例化DbContext");
            }
#endif
            this._efContext = efContext;
        }


        /// <summary>
        /// Entity Framework 的仓储实现资源释放
        /// </summary>
        /// <param name="disposing"></param>
        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                _efContext.Dispose();
            }
            base.Dispose(disposing);
        }


        /// <summary>
        /// Gets the <see cref="DbContext"/> instance handled by Entity Framework.
        /// </summary>
        public DbContext Context
        {
            get { return this._efContext; }
        }


        /// <summary>
        /// 注册一个即将添加的对象到下上文
        /// </summary>
        /// <typeparam name="TKey"></typeparam>
        /// <typeparam name="TAggregateRoot"></typeparam>
        /// <param name="obj"></param>
        public override void RegisterNew<TKey, TAggregateRoot>(TAggregateRoot obj)
        {
            obj = _efContext.Set<TAggregateRoot>().Add(obj);
            Committed = false;
        }
        /// <summary>
        /// 注册一个即将添加的对象到下上文
        /// </summary>
        /// <typeparam name="TKey"></typeparam>
        /// <typeparam name="TAggregateRoot"></typeparam>
        /// <param name="objs"></param>
        public override void RegisterNew<TKey, TAggregateRoot>(IEnumerable<TAggregateRoot> objs)
        {
            _efContext.Set<TAggregateRoot>().AddRange(objs);
            Committed = false;
        }
        /// <summary>
        /// 注册一个即将添加的对象到下上文
        /// </summary>
        /// <typeparam name="TKey"></typeparam>
        /// <typeparam name="TAggregateRoot"></typeparam>
        /// <param name="obj"></param>
        public override void RegisterModified<TKey, TAggregateRoot>(TAggregateRoot obj)
        {
            //this._efContext.Entry(obj).State = System.Data.Entity.EntityState.Modified;
            Committed = false;
        }
        /// <summary>
        /// 注册一个即将删除的对象到下上文
        /// </summary>
        /// <typeparam name="TKey"></typeparam>
        /// <typeparam name="TAggregateRoot"></typeparam>
        /// <param name="obj"></param>
        public override void RegisterDeleted<TKey, TAggregateRoot>(TAggregateRoot obj)
        {
            _efContext.Set<TAggregateRoot>().Remove(obj);
            Committed = false;
        }
        /// <summary>
        /// 执行Sql返回数据
        /// </summary>
        /// <typeparam name="TAggregateRoot"></typeparam>
        /// <param name="sqlQuery"></param>
        /// <param name="parameters"></param>
        /// <returns></returns>
        public IEnumerable<TAggregateRoot> ExecuteQuery<TAggregateRoot>(string sqlQuery, params object[] parameters)
        {
            return _efContext.Database.SqlQuery<TAggregateRoot>(sqlQuery, parameters);
        }
        /// <summary>
        /// 执行Sql
        /// </summary>
        /// <param name="sqlCommand"></param>
        /// <param name="parameters"></param>
        /// <returns></returns>
        public int ExecuteCommand(string sqlCommand, params object[] parameters)
        {
            return _efContext.Database.ExecuteSqlCommand(sqlCommand, parameters);
        }

        #region IUnitOfWork Members

        /// <summary>
        /// 是否支持分布式
        /// </summary>
        public override bool DistributedTransactionSupported
        {
            get { return true; }
        }
        /// <summary>
        /// 提交工作单元
        /// </summary>
        public override void Commit()
        {
            if (!Committed)
            {
                lock (_sync)
                {
                    try
                    {
                        _efContext.SaveChanges();
                    }
                    catch (DbUpdateException ex)
                    {
                        Exception innerException = ex.InnerException;
                        while (innerException != null)
                        {
                            if (innerException.InnerException != null)
                                innerException = innerException.InnerException;
                            else
                                throw new Exception(innerException.Message);
                        }

                    }
                    catch (DbEntityValidationException ex)
                    {

                        var dbEntityValidationResults = ex.EntityValidationErrors as DbEntityValidationResult[] ??
                                                        ex.EntityValidationErrors.ToArray();
                        StringBuilder sberr = new StringBuilder();
                        foreach (var item in dbEntityValidationResults)
                        {
                            sberr.AppendLine(item.Entry.Entity + "有错误");
                            foreach (var err in item.ValidationErrors)
                            {
                                sberr.AppendFormat("\t\t{0}:{1}\r\n", err.PropertyName, err.ErrorMessage);
                            }
                        }
                        Debug.WriteLine(sberr.ToString(), "数据库操作失败");
                        throw new Exception(sberr.ToString());

                        throw;
                    }
                    catch
                    {
                        throw;
                    }
                }
                Committed = true;
            }
        }
        /// <summary>
        /// 提交工作单元
        /// </summary>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        public override async Task CommitAsync(CancellationToken cancellationToken)
        {
            if (!Committed)
            {
                await _efContext.SaveChangesAsync(cancellationToken);
                Committed = true;
            }
        }

        /// <summary>
        /// 回滚当前的Unit Of Work事务
        /// </summary>
        public override void Rollback()
        {
            Committed = false;
        }

        #endregion
    }
}
